#ifndef __UDP_CLIENT_HPP__
#define __UDP_CLIENT_HPP__
#include "MyPthread/Log.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"
using namespace LogModule;

const static int gsockfd = -1;
class UdpClient
{
private:
    void *Recver(void *args)
    {
        // LOG(LogLevel::DEBUG) << "Recver begin, _sockfd: " << _sockfd;

        while (true)
        {
            // // 3. udpsocket是全双工的，但为什么需要temp接受回来的信息呢?
            // // UDP 是无连接协议，通信双方不需要建立持久连接。peer结构体在客户端中通常用于指定初始发送目标
            struct sockaddr_in temp;
            socklen_t len = sizeof(temp);
            char buffer[1024];

            int n = ::recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, CONV(&temp), &len);
            // LOG(LogLevel::DEBUG) << "recvfrom end";

            if (n > 0)
            {
                buffer[n] = 0;
                // LockGuard lockguard(_mutex);
                std::cerr << buffer << " n= " << n << std::endl;
            }
            else
            {
                LOG(LogLevel::DEBUG) << "recv nothing";
                break;
            }
        }
        return nullptr;
    }
    // 静态成员函数，作为线程入口
    static void *RecverStatic(void *arg)
    {
        UdpClient *client = static_cast<UdpClient *>(arg);
        // LOG(LogLevel::DEBUG) << "RecverStatic";

        return client->Recver(arg);
    }

public:
    UdpClient(std::string ip = server_ip, int port = server_port)
        : _sockfd(gsockfd), _server(server_ip, server_port)
    {
    }
    ~UdpClient()
    {
    }
    // 1. 创建socket
    void InitClient()
    {
        // 1. 创建socket
        _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            LOG(LogLevel::ERROR) << "socket error";
            Die(SOCKET_ERR);
        }
        // // 1.1 server地址，设置server段属性
        // _server.sin_family = AF_INET;                             // 协议族
        // _server.sin_port = ::htons(server_port);                  // 端口号
        // _server.sin_addr.s_addr = ::inet_addr(server_ip.c_str()); // 地址
    }
    void Start()
    {
        pthread_attr_t attr;
        struct sched_param param;
        int policy = SCHED_FIFO; // 实时调度策略
        // 初始化线程属性
        pthread_attr_init(&attr);
        // 设置线程调度策略
        pthread_attr_setschedpolicy(&attr, policy);
        // 设置优先级（1-99，数值越大优先级越高）
        param.sched_priority = 99;
        pthread_attr_setschedparam(&attr, &param);
        pthread_t tid;

        pthread_create(&tid, &attr, RecverStatic, (void *)this);

        // 1.2 启动的时候，给服务器推送消息即可
        const std::string online = " ... 来了哈!";
        int n = ::sendto(_sockfd, online.c_str(), online.size(), 0, CONV(&_server), sizeof(_server));

        // 2. clientdone
        while (true)
        {
            {
                // LockGuard lockguard(_mutex);
                std::cout << "Please Enter# ";
            }
            std::string message;
            std::getline(std::cin, message);

            int n = ::sendto(_sockfd, message.c_str(), message.size(), 0, CONV(&_server), sizeof(_server));
            (void)n;

            usleep(500000);
            // LOG(LogLevel::DEBUG) << "send succeed:" << message;
        }

        pthread_join(tid, nullptr);
    }

public:
private:
    int _sockfd;
    // struct sockaddr_in _client;
    InetAddr _server;
    Mutex _mutex;
};

#endif